# -*- coding: utf-8 -*-
import os
from functools import partial

import pysnooper
from PyQt5 import QtCore, QtGui, QtWidgets, Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QDockWidget, QAction, QFileDialog, QTreeWidget, QTreeWidgetItem, QDialog, QPushButton
import cv2
from moduleManager import *
from deviceManager import *
from projectManager import *
from projectDialog import *
from processDialog import *
from centerView import *
from imageManager import *
import configparser


class EmittingStream(QtCore.QObject):
    textWritten = QtCore.pyqtSignal(str)

    def write(self, text):
        self.textWritten.emit(str(text))

    def flush(self):
        pass


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.sourcepath = os.path.abspath(os.path.dirname(__file__))
        self.moduleMng = ModuleManager(self.sourcepath)
        self.modules = self.moduleMng.getModules()
        self.deviceMng = DeviceManager(self.sourcepath)
        self.devices = self.deviceMng.getDevices()
        self.projectHandle = ProjectManager()

        self.setupUi()

        if os.path.exists("config.ini"):
            self.config = configparser.ConfigParser()
            self.config.read('config.ini')
            project_cfg = self.config["project"]
            self.projectPath = project_cfg.get("path")
            if os.path.exists(self.projectPath):
                self.projectHandle.openProject(self.projectPath)
                self.updateTreeView()

        img_mng.update_signal.connect(self.updateImage)

    def setupUi(self):
        self.setObjectName("mainWindow")
        self.setWindowModality(QtCore.Qt.WindowModal)
        self.resize(800, 600)

        self.centralWidget = CenterView(self)
        self.centralWidget.setObjectName("centralWidget")
        self.centralWidget.show_message.connect(self.updateStatusMessage)
        self.setCentralWidget(self.centralWidget)
        self.centralWidget.setImgSize(self.centralWidget.size())

        self.projectWidget = QDockWidget(self)
        self.projectWidget.setObjectName("projectWidget")
        self.setupProjectWidget()
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.projectWidget)

        self.moduleWidget = QDockWidget(self)
        self.moduleWidget.setObjectName("moduleWidget")
        self.setupModuleWidget()
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.moduleWidget)

        self.consoleWidget = QDockWidget(self)
        self.consoleWidget.setObjectName("consolWidget")
        self.setupConsoleWidget()
        self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.consoleWidget)

        self.addAction()

        self.menuBar = QtWidgets.QMenuBar(self)
        self.menuBar.setGeometry(QtCore.QRect(0, 0, 630, 23))
        self.menuBar.setObjectName("menuBar")
        self.setupMenuBar()
        self.setMenuBar(self.menuBar)

        self.mainToolBar = QtWidgets.QToolBar(self)
        self.mainToolBar.setObjectName("mainToolBar")
        self.setupToolbar()
        self.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)

        self.statusBar = QtWidgets.QStatusBar(self)
        self.statusBar.setObjectName("statusBar")
        self.setStatusBar(self.statusBar)

        self.retranslateUi(self)
        QtCore.QMetaObject.connectSlotsByName(self)
        self.setWindowIcon(QIcon('logo.png'))

    def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
        self.update()
        self.centralWidget.setImgSize(self.centralWidget.size())

    def addAction(self):
        self.exitAction = QAction(QIcon('./images/exit.png'), 'Exit')
        self.exitAction.setShortcut('Ctrl+Q')
        self.exitAction.setStatusTip('Exit application')
        self.exitAction.triggered.connect(self.close)
        # 新建
        self.newAction = QAction(QIcon('./images/filenew.png'), 'New Project')
        self.newAction.setShortcut('Ctrl+N')
        self.newAction.setStatusTip('New application')
        self.newAction.triggered.connect(self.new)

        # 打开
        self.openAction = QAction(QIcon('./images/fileopen.png'), 'Open Project')
        self.openAction.setShortcut('Ctrl+O')
        self.openAction.setStatusTip('Open Application')
        self.openAction.triggered.connect(self.open)

        # 保存
        self.saveAction = QAction(QIcon('./images/filesave.png'), 'Save Project')
        self.saveAction.setShortcut('Ctrl+S')
        self.saveAction.setStatusTip('Save Application')
        self.saveAction.triggered.connect(self.save)

        # 撤销
        self.undoAction = QAction(QIcon('./images/undo.png'), 'Undo')
        self.undoAction.setShortcut('Ctrl+Z')
        self.undoAction.setStatusTip('Undo')
        # self.undoAction.triggered.connect(self.textEdit.undo)

        # 重做
        self.redoAction = QAction(QIcon('./images/redo.png'), 'Redo')
        self.redoAction.setShortcut('Ctrl+Y')
        self.redoAction.setStatusTip('Redo')
        # self.redoAction.triggered.connect(self.textEdit.redo)

        # 拷贝
        self.copyAction = QAction(QIcon('./images/editcopy.png'), 'Copy')
        self.copyAction.setShortcut('Ctrl+C')
        self.copyAction.setStatusTip('Copy')
        self.copyAction.triggered.connect(self.copy)

        # 粘贴
        self.pasteAction = QAction(QIcon('./images/editpaste.png'), 'Paste')
        self.pasteAction.setShortcut('Ctrl+V')
        self.pasteAction.setStatusTip('Paste')
        self.pasteAction.triggered.connect(self.paste)

        # 剪切
        self.cutAction = QAction(QIcon('./images/editcut.png'), 'Cut')
        self.cutAction.setShortcut('Ctrl+X')
        self.cutAction.setStatusTip('Cut')
        self.cutAction.triggered.connect(self.cut)

        self.delAction = QAction(QIcon('./images/delete.png'), 'Delete')
        self.delAction.setShortcut('Del')
        self.delAction.setStatusTip('delete module')
        self.delAction.triggered.connect(self.deleteModule)

        self.runAction = QAction(QIcon('./images/start.png'), 'Run')
        self.runAction.setShortcut('Run')
        self.runAction.setStatusTip('run module')
        self.runAction.triggered.connect(self.run)

        self.stopAction = QAction(QIcon('./images/stop.png'), 'Stop')
        self.stopAction.setShortcut('Stop')
        self.stopAction.setStatusTip('stop module')
        self.stopAction.triggered.connect(self.stop)

        self.uploadAction = QAction(QIcon('./images/editcut.png'), 'Upload Tool')
        self.uploadAction.triggered.connect(self.uploadTool)

        self.downloadAction = QAction(QIcon('./images/editcut.png'), 'Download Tool')
        self.uploadAction.triggered.connect(self.downloadTool)

        # 关于
        self.aboutAction = QAction(QIcon('./images/about.png'), 'About')
        self.aboutAction.setStatusTip('About')
        self.aboutAction.triggered.connect(self.about)

    # @pysnooper.snoop()
    def setupMenuBar(self):
        fileMenu = self.menuBar.addMenu('&File')
        fileMenu.addAction(self.newAction)
        fileMenu.addAction(self.openAction)
        fileMenu.addAction(self.saveAction)
        fileMenu.addAction(self.exitAction)

        editMenu = self.menuBar.addMenu('&Edit')
        editMenu.addAction(self.undoAction)
        editMenu.addAction(self.redoAction)
        editMenu.addAction(self.cutAction)
        editMenu.addAction(self.copyAction)
        editMenu.addAction(self.pasteAction)

        toolMenu = self.menuBar.addMenu('&Tools')
        toolMenu.addAction(self.uploadAction)
        toolMenu.addAction(self.downloadAction)

        deviceMenu = self.menuBar.addMenu('&Device')
        actions_dev: list = []
        for i in range(len(self.devices)):
            name = self.devices[i].MenuText
            clazz = self.devices[i].clazz
            clazz.setPlatform(self)
            iconPath = self.devices[i].Icon
            ac = QAction(QIcon(iconPath), name, deviceMenu)
            ac.triggered.connect(partial(self.loadDeviceGui, name))
            actions_dev.append(ac)
        deviceMenu.addActions(actions_dev)

        moduleMenu = self.menuBar.addMenu("&Module")
        actions_module: list = []
        for i in range(len(self.modules)):
            name = self.modules[i].MenuText
            clazz = self.modules[i].clazz
            clazz.setPlatform(self)
            iconPath = self.modules[i].Icon
            ac = QAction(QIcon(iconPath), name, moduleMenu)
            ac.triggered.connect(partial(self.loadModuleGui, name))
            actions_module.append(ac)
        moduleMenu.addActions(actions_module)

        helpMenu = self.menuBar.addMenu('&Help')
        helpMenu.addAction(self.aboutAction)

    # @pysnooper.snoop()
    def setupToolbar(self):
        self.mainToolBar.addAction(self.exitAction)
        self.mainToolBar.addAction(self.openAction)
        self.mainToolBar.addAction(self.newAction)
        self.mainToolBar.addAction(self.saveAction)
        self.mainToolBar.addSeparator()
        self.mainToolBar.addAction(self.delAction)
        self.mainToolBar.addAction(self.runAction)
        self.mainToolBar.addAction(self.stopAction)
        self.mainToolBar.addSeparator()

    def uploadTool(self):
        pass

    def downloadTool(self):
        pass

    def loadDeviceGui(self, device_name):
        if self.projectHandle is None:
            self.statusBar.showMessage("Please Create ONE Project Firstly.")
            return
        dialog = CreateProcessDialog(self.projectHandle)
        dialog.exec_()  # 显示对话框
        if dialog.getReturnValue():
            for i in range(len(self.devices)):
                if device_name == self.devices[i].MenuText:
                    self.devices[i].clazz.setPlatform(self)
                    para = None
                    func_id = self.projectHandle.getIndex()
                    self.devices[i].clazz.Initialize(func_id + 1, para)
                    self.projectHandle.addDevice(self.devices[i].name, para)
                    self.updateTreeView()
                    break

    def loadModuleGui(self, module_name):
        if self.projectHandle is None:
            self.statusBar.showMessage("Please Create ONE Process Firstly.")
            return
        for i in range(len(self.modules)):
            if module_name == self.modules[i].MenuText:
                self.modules[i].clazz.setPlatform(self)
                para = None
                func_id = self.projectHandle.getIndex()
                self.modules[i].clazz.Initialize(func_id + 1, para)
                self.projectHandle.addFunction(self.modules[i].name, para)
                self.updateTreeView()
                break

    def appendMenu(self, name, func):
        self.modules[self.curModuleIndex].appendMenu(name, func)

    def appendToolbar(self, name, func):
        self.modules[self.curModuleIndex].appendToolbar(name, func)

    def addFunction(self, name, para):
        self.projectHandle.addFunction(name, para)
        self.updateTreeView()

    def deleteModule(self):
        item = self.tree.currentItem()
        func_id = int(item.text(1))
        module_name = item.text(0)
        self.projectHandle.deleteModule(func_id, module_name)
        self.updateTreeView()

    def updateStatusMessage(self, msg: str):
        self.statusBar.showMessage(msg)

    def updateImage(self, qimg: QImage):
        self.centralWidget.updateImageLabel(qimg)

    def updateRunPara(self, module_index: int, module_para: dict):
        print(module_index,module_para)
        self.projectHandle.updateModulePara(module_index, module_para)

    def updateTreeView(self):
        self.tree.clear()
        root = QTreeWidgetItem(self.tree)
        root.setText(0, self.projectHandle.getProjectName())
        process_list = self.projectHandle.getProcessList()
        for proc in process_list:
            child1 = QTreeWidgetItem(root)
            child1.setText(0, proc.process_name)
            child1.setText(1, "%d" % proc.index)
            for func in proc.func_list:
                child2 = QTreeWidgetItem(child1)
                child2.setText(0, func.func_name)
                child2.setText(1, "%d" % func.index)
        self.tree.addTopLevelItem(root)
        self.tree.expandAll()

    def onTreeClicked(self, qmodelindex):
        item = self.tree.currentItem()
        clazz = self.deviceMng.getDeviceHandleByName(item.text(0))
        if clazz:
            clazz.setPlatform(self)
            para = self.projectHandle.getFunctionParas(int(item.text(1)))
            index = int(item.text(1))
            clazz.Initialize(index, para)
        else:
            clazz = self.moduleMng.getModuleHandleByName(item.text(0))
            if clazz:
                para = self.projectHandle.getFunctionParas(int(item.text(1)))
                index = int(item.text(1))
                clazz.setPlatform(self)
                clazz.Initialize(index, para)

    def setupProjectWidget(self):
        self.tree = QTreeWidget()
        root = QTreeWidgetItem(self.tree)
        self.tree.setColumnCount(2)
        self.tree.setHeaderLabels(['name', 'index'])
        self.tree.addTopLevelItem(root)
        self.projectWidget.setWidget(self.tree)
        self.tree.clicked.connect(self.onTreeClicked)

    def setupModuleWidget(self):
        lb = QtWidgets.QLabel("add")
        self.moduleWidget.setWidget(lb)

    def setupConsoleWidget(self):
        self.consoleText = QtWidgets.QTextEdit()
        self.consoleWidget.setWidget(self.consoleText)
        # sys.stdout = EmittingStream(textWritten=self.consoleOutput)

    def __del__(self):
        pass
        # sys.stdout = sys.__stdout__

    def consoleOutput(self, text):
        cursor = self.consoleText.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.insertText(text)
        self.consoleText.setTextCursor(cursor)
        self.consoleText.ensureCursorVisible()

    def retranslateUi(self, mainWindow):
        _translate = QtCore.QCoreApplication.translate
        mainWindow.setWindowTitle(_translate("MainWindow", "OpenVison"))
        self.centralWidget.setWindowTitle(_translate("MainWindow", "Image"))
        self.consoleWidget.setWindowTitle(_translate("MainWindow", "Console"))
        self.moduleWidget.setWindowTitle(_translate("MainWindow", "Module"))
        # self.label.setText(_translate("MainWindow", "用户名"))
        # self.label_2.setText(_translate("MainWindow", "密码"))
        # self.login_btn.setText(_translate("MainWindow", "登陆"))
        # self.actionlist.setText(_translate("MainWindow", "list"))
        # self.actionlis2.setText(_translate("MainWindow", "lis2"))
        # self.actionlist3.setText(_translate("MainWindow", "list3"))

    def new(self):
        self.statusBar.showMessage('Create Image Process Project')
        dialog = CreateProjectDialog(self.projectHandle)
        dialog.exec()  # 显示对话框
        self.updateTreeView()

    def open(self):
        self.statusBar.showMessage('Open Project Files')
        fname = QFileDialog.getOpenFileName(self, 'Open file', '.', "*.prj")
        self.statusBar.showMessage('Open Project File')
        if fname[0]:
            self.projectPath = fname[0]
            self.projectHandle.openProject(fname[0])
            self.updateTreeView()

    def close(self):
        self.projectHandle.closeProject()
        self.projectHandle = None

    # save
    def save(self):
        self.statusBar.showMessage('Add extension to file name')
        fname = self.projectHandle.getProjectName()
        if fname:
            self.projectHandle.saveProject()
            self.projectPath = self.projectHandle.getProjectPath()
            config = ConfigParser()
            config.add_section('project')
            prj_info = os.path.join(self.projectPath, self.projectHandle.getProjectName()+".prj")
            config.set("project", "path", prj_info)
            fo = open("config.ini", 'w', encoding='UTF-8')
            config.write(fo)
            fo.close()
    # copy
    def copy(self):
        pass
        # cursor = self.textEdit.textCursor()
        # textSelected = cursor.selectedText()
        # self.copiedText = textSelected

    # paste
    def paste(self):
        pass
        # self.textEdit.append(self.copiedText)

    # cut
    def cut(self):
        pass
        # cursor = self.textEdit.textCursor()
        # textSelected = cursor.selectedText()
        # self.copiedText = textSelected
        # self.textEdit.cut()

    # about
    def about(self):
        url = 'https://en.wikipedia.org/wiki/Text_editor'
        self.statusBar.showMessage('Loading url...')
        # webbrowser.open(url)

    def run(self):
        proc_list = self.projectHandle.getProcessList()
        for proc in proc_list:
            for func in proc.func_list:
                name = func.func_name
                fun_id = func.index
                clazz = self.deviceMng.getDeviceHandleByName(name)
                if clazz:
                    clazz.setPlatform(self)
                    clazz.initRunEnv()
                    para = self.projectHandle.getFunctionParas(fun_id)
                    clazz.run(para)
                else:
                    clazz = self.moduleMng.getModuleHandleByName(name)
                    if clazz:
                        clazz.setPlatform(self)
                        clazz.initRunEnv()
                        para = self.projectHandle.getFunctionParas(fun_id)
                        clazz.run(para)

    def stop(self):
        pass


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    ui = MainWindow()
    ui.show()
    sys.exit(app.exec_())
